Apple, the Apple logo, and Macintosh are registered trademarks of Apple Computer, Inc.
Mac and OpenDoc are trademarks of Apple Computer, Inc.
Introduction
This document describes the basics of event distribution to parts. It describes the events a part will need to handle, but does not describe in great detail what should be done with each event. This is heavily content-dependent, and will often be apparent to Macintosh developers. This section also does not deal with semantic events.
See also:
Window Events
Mouse Events
Menus
Windows and Dialogs
Drag and Drop
The OpenDoc shell and container applications contain an event loop, and call ODDispatcher::Dispatch() to deliver events to parts. This method takes an event record and returns a Boolean value. If the returned value is kODFalse, the shell may handle the event, otherwise a part, or the dispatcher itself has handled the event.
The dispatcher contains a table of dispatch modules. The dispatcher locates a dispatch module for a given event, and the dispatch module calls one of the following ODPart methods, shown here in IDL:
void Draw(in ODFacet facet,
in ODShape invalidShape);
ODBoolean HandleEvent(inout ODEventData event,
in ODFrame frame,
in ODFacet facet,
inout ODEventInfo eventInfo);
New in DR2: ODEventInfo has the following definition:
struct ODEventInfo
{
ODFrame embeddedFrame;
ODFacet embeddedFacet;
ODPoint where;
ODBoolean propagated;
};
New in DR2: Since the DR1 release of OpenDoc, HandleEventInEmbedded, MouseEnter, MouseWithin and MouseLeave have been removed. Instead, HandleEvent takes the extra eventInfo parameter which contains the embedded frame and facet which were passed to HandleEventInEmbedded, and the ODPoint which was passed to MouseEnter and MouseWithin.
The frame and facet parameters of HandleEvent() may be kODNULL, depending on the kind of event. The embeddedFrame and embeddedFacet fields of ODEventInfo will also be kODNULL except for certain kinds of events. See the notes on particular events below.
Standard Macintosh Events
Part editors must handle the following events, which correspond to standard Macintosh events:
kODEvtNull
kODEvtMouseDown
kODEvtMouseUp
kODEvtKeyDown
kODEvtKeyUp
kODEvtAutoKey
kODEvtUpdate
kODEvtActivate
kODEvtOS
Additional OpenDoc Events
OpenDoc part editors must handle the following additional events:
kODEvtMenu // Mouse down in the menu bar
kODEvtWindow // Mouse down in the window title bar. Close menu item.
kODEvtMouseEnter // Mouse moved into a frame for the first time
kODEvtMouseWithin // Mouse moved within a frame
kODEvtMouseLeave // Mouse moved outside a frame
kODEvtBGMouseDown // Mouse down in an inactive (background) document
Part editors which support embedding must also handle the following events:
kODEvtMouseDownEmbedded // Mouse down in a selected, bundled or iconic frame
kODEvtBGMouseDownEmbedded // As above, in an inactive (background) document
kODEvtMouseUpEmbedded // Mouse up in a selected, bundled or iconic frame
kODEvtMouseDownBorder // Mouse down in the active frame border
Read-Only Documents
Note: Part Editors will need to disable certain portions of their event handling when a draft is read-only. See the Init Part and Externalize recipe for information on draft permissions.
Standard Macintosh Events
Idle Time (Null Events)
In order to receive null events (i.e. idle time), parts must call ODDispatcher::RegisterIdle(), specifying the part (actually part wrapper), a frame and an idle frequency.
The frame can be kODNULL. If frames are registered, the part will receive a null event for each frame registered. The idle frequencies are used in the computation of the sleep time passed to WaitNextEvent. Idle frames might be registered in Part::DisplayFrameAdded() and Part::DisplayFrameConnected(), or perhaps in Part::FacetAdded(). Idle frames should be unregistered before the frame is destroyed, such as in DisplayFrameClosed() and DisplayFrameRemoved().
In addition to the standard mouse down and mouse up events, part editors which support embedding must deal with mouse events in embedded frames which are selected, bundled or viewed as icons or thumbnails. Part editors must also handle special background mouse events to support Drag and Drop. See Mouse Events and Drag and Drop recipes.
Keyboard Events
Keyboard events go to the frame with the keyboard focus, with the exception of the Page Up, Page Down, Home and End keys, which will go to the frame with the scrolling focus, if there is one.
Update Events
Update events are not passed to Part::HandleEvent(). Rather ODPart::Draw() will be called once for each facet in the window. See the sample code and the Imaging recipes for examples of drawing.
Activate Events
Activate events are also delivered to each facet in a window, using Part::HandleEvent(). The facets are traversed bottom up. i.e. the root facet comes last.
case kODEvtActivate:
wasHandled = true; // actually ignored by dispatcher
fNeedsFoci = kODTrue; // I want to be active when my window is
}
else
fNeedsFoci = kODFalse;
}
Disk Events
Currently, disk events are not distributed to parts.
OS Events
Suspend/Resume events are delivered to each facet in each window using Part::HandleEvent().
A part should hide dialogs and palettes when switching to the background, and show them again when returning to the foreground.
Mouse Moved events are turned in the events kODEvtMouseEnter, kODEvtMouseWithin and kODEvtMouseLeave which are described in the next section.
Additional OpenDoc Events
Menu Events
OpenDoc converts a mouse down in the menu bar, or its command-key equivalent, into a menu event of type kODEvtMenu.
The message field of the event record contains the result returned by MenuSelect() or MenuKey(). i.e. the menu is in the high word, and the item in the low word. The part can obtain a command number from the menu and item using ODMenuBar::GetCommand().
See Menus recipe for more details.
Window Events
Events in the title bar of a window are delivered to the root part of that window as an event of type kODEvtWindow. The message field of the event contains the part code, as returned by FindWindow(). See Window Events recipe.
Mouse Moved Events
New in DR2: The following ODPart methods have been removed:
void MouseEnter(in ODFacet facet,
in ODPoint where);
void MouseWithin(in ODFacet facet,
in ODPoint where);
void MouseLeave(in ODFacet facet);
Instead there are three new events kODEvtMouseEnter, kODEvtMouseWithin and kODEvtMouseLeave which are passed to HandleEvent() along with a frame and facet. The "where" value is included in the eventInfo struct, and contains a point in local (frame) coordinates.
OpenDoc tracks cursor movement (with the mouse button up), and delivers a kODEvtMouseEnter event to the frame under the mouse when the cursor first moves into one of its facets. If the mouse moves within a frame, a kODEvtMouseWithin event is sent, and when the mouse moves outside of the facet, a kODEvtMouseLeave event is sent. A part editor will typically change the cursor on receiving a kODEvtMouseEnter and kODEvtMouseWithin, and set it to the arrow on kODEvtMouseLeave.
These events are triggered by the shell calling ODDispatcher::GetMouseRegion() to determine a sleep region to pass to WaitNextEvent(). The region is only recomputed when it has been invalidated, such as when the shell receives a mouseMoved event from the system. Part Editors can also invalidate the region by calling the ODDispatcher method:
void InvalidateFacetUnderMouse();
By default, OpenDoc computes a mouse region containing just the cursor location. If the cursor is motionless within a facet, the shell application can go to sleep. A part editor can make this region larger by calling the ODDispatcher method:
void SetMouseRegion(in ODRgnHandle area);
The region is in global (screen) coordinates.
In a future release, if the cursor is not within any facet, OpenDoc should compute a suitably large sleep region (i.e. screen minus content regions of OpenDoc windows).
A containing part is responsible for for setting the cursor to the hand cursor over the active border:
if (facet->ActiveBorderContainsPoint(ev,&framePoint,kODNULL))
{
cursorInActiveBorder = kODTrue;
break;
}
}
ODDeleteObject(iter);
}
if (cursorInActiveBorder)
{
ODSLong savedRefNum;
BeginUsingLibraryResources(savedRefNum);
SetCursor(*GetCursor(283)); // Hand Cursor
EndUsingLibraryResources(savedRefNum);
}
else
SetCursor(*GetCursor(crossCursor)); // For now.
}
handled = kODTrue;
break;
Mouse Events in Embedded Frames
See Mouse Events recipe.
Special Considerations
The Modal Focus
Some events are constrained by the modal focus. A mouse click outside the frame with the modal focus will be sent to the modal focus frame, but a click in an embedded frame within the modal focus frame will still go to the embedded frame. When the user clicks outside the modal frame, a facet of kODNULL is passed to HandleEvent(). The part editor should check for this value, and beep or dismiss the dialog as desired.
See Dialogs recipe for more about the modal focus.
The Mouse Focus (New in DR4)
For modal situations, like a polygon drawing tool, the mouse focus captures mouse down, mouse up and mouse moved events. See Mouse Events recipe.
Propagating Events
This feature of OpenDoc is not likely to be used by most parts. If a containing part sets the “DoesPropagateEvents” property of an embedded frame, the containing part will receive events not handled by the embedded frame, via the HandleEvent() method.